package com.jl.card.provider.jl2g;

import com.jl.card.Card;
import com.jl.card.ErrorProcess;
import com.jl.card.ISTK;
import com.jl.card.JL;
import com.jl.card.parse.SimpleAnalyse;
import com.jl.card.util.APDUUtil;
import com.jl.card.util.SimpleTLV;
import com.jl.card.util.SimpleTag;
import com.jl.util.HexUtil;
import com.jl.util.LengthUtil;

public class JL2GSTK implements ISTK {

	private STKUIControl entry;

	private Card card;
	private byte[] response;

	private int proCmdType = JL.STK_CLOSE;
	private int proCmdDetail = 0x00;

	private STKUIControl ui;

	public JL2GSTK(Card card) {
		this.card = card;
	}

	@Override
	public void on() {
		off();// clear resource
		card.reset(false);
		if (proCmdType != JL.STK_CLOSE) {
			return;
		}
		sendCommand(makeTerminalProfileCommand());
		// TERMINAL RESPONSE
		if (proCmdType == JL.STK_SET_UP_EVENT_LIST) {
			sendCommand(makeTerminalResponse(HexUtil
					.parseHexToByteArray("81 03 01 05 00 82 02 82 81 83 01 00")));
		}
		if (proCmdType == JL.STK_SHOW_MENU) {
			entry = ui;
			sendCommand(makeTerminalResponse(new byte[] { (byte) 0x81,
					(byte) 0x03, (byte) 0x01, (byte) 0x25, (byte) 0x00,
					(byte) 0x82, (byte) 0x02, (byte) 0x82, (byte) 0x81,
					(byte) 0x83, (byte) 0x01, (byte) 0x00 }));
			if (entry == null || entry.getAllItems().length == 0) {
				proCmdType = JL.STK_NO_MENU_ENTRY;
			}
		}
	}

	@Override
	public void select(int index) {
		if (proCmdType == JL.STK_SHOW_MENU) {
			// ENVELOPE
			// A0C2000009 D307820201819001 id
			byte id = entry.getItems().get(index - 1).getID();
			sendCommand(makeEnvlope(new byte[] { (byte) 0xD3, (byte) 0x07,
					(byte) 0x82, (byte) 0x02, (byte) 0x01, (byte) 0x81,
					(byte) 0x90, (byte) 0x01, id }));
		} else if (proCmdType == JL.STK_SELECT_ITEM) {
			// TERMINAL RESPONSE
			// A01400000F 8103012400820282818301009001 id
			byte id = ui.getItems().get(index - 1).getID();
			sendCommand(makeTerminalResponse(new byte[] { (byte) 0x81,
					(byte) 0x03, (byte) 0x01, (byte) 0x24, (byte) 0x00,
					(byte) 0x82, (byte) 0x02, (byte) 0x82, (byte) 0x81,
					(byte) 0x83, (byte) 0x01, (byte) 0x00, (byte) 0x90,
					(byte) 0x01, id }));
		}
	}
	
	@Override
	public void selectByText(String text) {
		STKUIControl temp =  proCmdType == JL.STK_SHOW_MENU ? entry : ui;
		int index = 0;
		for(Item one : temp.getItems()){
			if(one.getText().trim().equals(text.trim())){
				select(index + 1);
				return;
			}
			index++;
		}
		ErrorProcess.throwRuntimeException("the select item : " + text + " not exist");
		
	}

	@Override
	public void ok() {
		byte[] data = new byte[] { (byte) 0x81, 0x03, 0x01,
				(byte) (proCmdType & 0xFF), (byte) (proCmdDetail & 0xFF),
				(byte) 0x82, 0x02, (byte) 0x82, (byte) 0x81, (byte) 0x83, 0x01,
				0x00 };
		byte[] cmd = makeTerminalResponse(data);
		sendCommand(cmd);
	}

	@Override
	public void back() {
		// 810301210082028281830111
		byte[] data = new byte[] { (byte) 0x81, 0x03, 0x01,
				(byte) (proCmdType & 0xFF), (byte) (proCmdDetail & 0xFF),
				(byte) 0x82, 0x02, (byte) 0x82, (byte) 0x81, (byte) 0x83, 0x01,
				0x11 };
		byte[] cmd = makeTerminalResponse(data);
		sendCommand(cmd);
	}

	@Override
	public void input(String data) {
		// 81 03 01 23 01 82 02 82 81 83 01 00 8D 02 coing data
		if (proCmdType == JL.STK_GET_INPUT || proCmdType == JL.STK_GET_INKEY) {
			byte[] _byte = new byte[] { (byte) 0x81,
					(byte) 0x03, (byte) 0x01, (byte) (proCmdType & 0xFF), (byte) 0x01,
					(byte) 0x82, (byte) 0x02, (byte) 0x82, (byte) 0x81,
					(byte) 0x83, (byte) 0x01, (byte) 0x00 };
			SimpleTLV input = new SimpleTLV(null, _byte);
			byte coding = 0x00;
			if ((proCmdDetail & 0x02) == 0x02) {
				coding = 0x08;
			} else {
				coding = 0x04;
			}
			byte[] text = STKUtil.makeTextWithCodingByte(data, coding);
			input.concat(new SimpleTag((byte) 0x8D, true), text);
			sendCommand(makeTerminalResponse(input.toBinary()));
		}
	}

	@Override
	public String show() {
		if (proCmdType == JL.STK_CLOSE) {
			return "[#Power Off, Please On#]";
		}
		if (proCmdType == JL.STK_NO_MENU_ENTRY) {
			return "[#No Menu#]";
		}
		if (proCmdType == JL.STK_SHOW_MENU) {
			return entry.show();
		}
		return ui.show();
	}

	/**
	 * clear resource
	 */
	@Override
	public void off() {
		proCmdType = JL.STK_CLOSE;
		ui = null;
		entry = null;
	}

	private void sendCommand(byte[] cmd) {
		response = card.plainAPDU(cmd);
		if (SimpleAnalyse.sw1(response) == (byte) 0x91) {
			// FETCH
			response = card.plainAPDU(makeFetch(response[1]));
			byte[] data = SimpleAnalyse.data(response);
			ui = new STKUIControl(data);
			proCmdType = ui.getType();
			proCmdDetail = ui.getQualifier();
		} else {
			proCmdType = JL.STK_SHOW_MENU;
		}
	}

	protected byte[] makeTerminalProfileCommand() {
		byte[] cmd = new byte[] { (byte) 0xA0, 0x10, 0x00, 0x00, 0x06,
				(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
				(byte) 0xFF, (byte) 0xFF };
		return cmd;
	}

	protected byte[] makeTerminalResponse(byte[] data) {
		return APDUUtil.make((byte) 0xa0, (byte) 0x14, (byte) 0x00,
				(byte) 0x00, data);
	}

	protected byte[] makeEnvlope(byte[] data) {
		return APDUUtil.make((byte) 0xa0, (byte) 0xc2, (byte) 0x00,
				(byte) 0x00, data);
	}

	protected byte[] makeFetch(byte len) {
		return new byte[] { (byte) 0xa0, 0x12, 0x00, 0x00, len };
	}

	@Override
	public void envelop(String data) {
		data = LengthUtil.replace(data);
		byte[] bData = HexUtil.parseHexToByteArray(data);
		sendCommand(makeEnvlope(bData));
	}

	@Override
	public STKUIControl getUI() {
		if (proCmdType == JL.STK_SHOW_MENU) {
			return entry;
		}
		return ui;
	}


}

class Item {
	private byte id;
	private String text;

	public Item(SimpleTLV tlv) {
		byte[] value = tlv.valueAsByteArray();
		id = (byte) (value[0] & 0xFF);
		text = STKUtil.parseItemText(value, 1, value.length - 1);
	}

	public byte getID() {
		return id;
	}

	public String getText() {
		return text;
	}

}

